#include "sbrush_player.h"
#include "dag_threading.h"
#include <stddef.h>

using namespace sbrush;
using namespace dag;
namespace sbrush {
	class FinishedSignaller : public Runnable {
	public:
		FinishedSignaller()
		:	m_Callback(NULL),
			m_Player(NULL),
			m_UserData(NULL),
			m_IsWaiting(false),
			m_KeepWaiting(true)
		{
		}
		
		virtual ~FinishedSignaller() throw() {
			if (m_IsWaiting) { 
				cancelThread();
			}
		}
		void startSignalling() {
			m_KeepWaiting = true;
			startThread();
		}
		
		void stopSignalling() {
			ScopedLock sl(m_SignalMutex);
			m_Callback = NULL;
			m_Player = NULL;
			m_UserData = NULL;
			m_KeepWaiting = false;
			m_SignalCondition.signal();
		}
		
		void didFinish(player_finished_cb callback, 
					   const Player* player, 
					   void* userData) {
			ScopedLock sl(m_SignalMutex);
			m_Callback = callback;
			m_Player = player;
			m_UserData = userData;
			m_SignalCondition.signal();
		}
		
		void runThread() {
			while (m_KeepWaiting) {
				m_IsWaiting = true;
				ScopedLock sl(m_SignalMutex);
				m_SignalCondition.wait(m_SignalMutex);
				m_IsWaiting = false;
				
				if (m_Callback != NULL) {
					(*m_Callback)(m_Player, m_UserData);
				}
			}
		}
		
	private:
		bool m_KeepWaiting;
		bool m_IsWaiting;
		Mutex m_SignalMutex;
		Condition m_SignalCondition;
		player_finished_cb m_Callback;
		const Player* m_Player;
		void* m_UserData;
	};
}

Player::Player()
:	m_Callback(NULL),
	m_UserData(NULL),
	m_Signaller(NULL)
{
	m_Signaller = new FinishedSignaller();
	m_Signaller->startSignalling();
}

Player::~Player() throw() {
	m_Signaller->stopSignalling();
	delete m_Signaller;
}

void Player::finished() const {
	m_Signaller->didFinish(m_Callback, this, m_UserData);
}

void Player::setFinishedCallback(player_finished_cb callback, void* userData) {
	m_Callback = callback;
	m_UserData = userData;
}
